package upm.pb4agent.team5.custom;

import jade.content.Concept;
import jade.core.AID;
import jade.core.behaviours.CyclicBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.util.leap.ArrayList;
import upm.pb4agent.ontology.AssignBoat;
import upm.pb4agent.ontology.DenyRow;
import upm.pb4agent.ontology.EnteringDock;
import upm.pb4agent.ontology.PickSeat;
import upm.pb4agent.ontology.RaceFinished;
import upm.pb4agent.ontology.RaceStarted;
import upm.pb4agent.ontology.RealRow;
import upm.pb4agent.team5.common.Boat;
import upm.pb4agent.team5.util.RowerWrapper;

public class BRowerManageMessages extends CyclicBehaviour {
	private static final long serialVersionUID = 6134751688914039812L;

	private Rower rower = null;
	private RowerRowStrategy rowStrategy = null;

	public BRowerManageMessages(Rower rower) {
		this.rower = rower;
	}
	
	@Override
	public void action() {
		if (rowStrategy == null) // Initializing RowStrategy
			rowStrategy = new RowerRowStrategy(rower); 

		ACLMessage msg = rower.blockingReceive(getTemplate());
		
		try {
			if (msg.getProtocol().equals(Rower.ACTIVATE_PROTOCOL)) {
				rower.setInBoat(true);
				return; // Returning before trying to getConcept
			} else if (msg.getProtocol().equals(Rower.SEND_KI_PROTOCOL)) {
				// Changing ki for previous rower
				AID previousRower = msg.getSender();
				changeRowerWrapperKi(previousRower, Float.parseFloat(msg.getContent()));
				
				rower.send(rower.getSeat(), previousRower, ACLMessage.INFORM, Rower.CHANGE_SEAT_PROTOCOL);
				rowStrategy.requestPickSeat(rowStrategy.getBestSeatToRow());
				
				rower.setRowing(true);
				
				System.out.println(rower.getLocalName() + ": Now active. Previous rower: " + previousRower.getLocalName()); 
				new Thread(rowStrategy).start(); // Starting thread for rowing				

				return;
			} else if (msg.getProtocol().equals(Rower.CHANGE_SEAT_PROTOCOL)) {
				String newSeat = msg.getContent();

				rower.setRowing(false);
				rowStrategy.setChangedStrategy(true); // Stopping thread for rowing
				rowStrategy.requestPickSeat(newSeat);
				
				return;
			}
			
			Concept concept = rower.getConcept(msg);

			if (concept instanceof RaceStarted) { // Communicated by Referee
				System.out.println(rower.getLocalName() + ": Race started");
				
				if (rower.isInBoat()) {
					rower.setRowing(true);
					new Thread(rowStrategy).start(); // Start rowing
				}
				
			} else if (concept instanceof AssignBoat) { // Communicated by Watcher
				// Setting initial ki
				jade.util.leap.List rowers = new ArrayList();
				for (int i = 0; i < Rower.DF_NAME.length; i++)
					rowers.add(rower.findAID(Rower.DF_NAME[i]));

				rower.setRowersWrapper(Manager.getRowersOrderedByStaringKi(rowers));

				rowStrategy.assignBoat((AssignBoat) concept);
			} else if (concept instanceof RealRow) { // Communicated by Watcher
				RealRow realRow = (RealRow) concept;
				
				// Updating number of rows for calculating new ki
				rower.incrementNumberOfRows();
				changeRowerWrapperKi(rower.getAID(), rower.getKi());
				
				System.out.println(rower.getLocalName() + ": Rowing to (x=" + realRow.getX() + 
					", y=" + realRow.getY() + ")");
			} else if (concept instanceof DenyRow) { // Communicated by Watcher
				DenyRow denyRow = (DenyRow) concept;
				System.out.println(rower.getLocalName() + ": Rowing denied for oar: " + denyRow.getOarID());				
			} else if (concept instanceof PickSeat) { // Communicated by Watcher (deprecated). Alejandro's proposal
				PickSeat pickSeat = (PickSeat) concept;
				
				if (msg.getPerformative() == ACLMessage.INFORM) 
					System.out.println(rower.getLocalName() + ": Request Pick Seat accepted for seatId=" + pickSeat.getSeatID().getSeatID());
				else // ACLMessage.REFUSE 
					System.out.println(rower.getLocalName() + ": Request Pick Seat denied for seatId=" + pickSeat.getSeatID().getSeatID());
			} else if (concept instanceof EnteringDock) { // Communicated by Referee
				EnteringDock enteringDock = (EnteringDock) concept;
				System.out.println(rower.getLocalName() + ": EnteringDock at position " + enteringDock.getPosition());
				
				// Only if the message is for Rowers of Team 5
				if (enteringDock.getBoatAID().getLocalName().equals(rower.getBoat().getID().getLocalName())) {
					rower.getDocks().add(enteringDock.getDock());
					
					// Activate new rower
					int index = rower.getDocks().size() - 1;
					RowerWrapper actualRower = rower.getRowersWrapper().get(index);
					if (actualRower.getRowerAID().getLocalName().equals(rower.getDfName())) {
						if (rowStrategy.getBestSeatToRow().equals(Boat.SEAT_ID[1])) {
							if (index==1) 
								rowStrategy.requestPickSeat(Boat.SEAT_ID[3]);
							else if (index==2) 
								rowStrategy.requestPickSeat(Boat.SEAT_ID[4]);
							else
								rowStrategy.requestPickSeat(Boat.SEAT_ID[5]);
						} else {
							if (index==1) 
								rowStrategy.requestPickSeat(Boat.SEAT_ID[0]);
							else if (index==2) 
								rowStrategy.requestPickSeat(Boat.SEAT_ID[1]);
							else
								rowStrategy.requestPickSeat(Boat.SEAT_ID[2]);
						}
						
						rower.setInBoat(true);
					}
					
				}
			} else if (concept instanceof RaceFinished) { // Communicated by Referee
				RaceFinished raceFinished = (RaceFinished) concept;

				if (raceFinished.getBoatAID().getLocalName().equals(rower.getBoat().getID().getLocalName())) {
					rower.setRowing(false);
					rowStrategy.setChangedStrategy(true); // stop rowing
					
					System.out.println(rower.getLocalName() + ": RaceFinished at position " + raceFinished.getPosition() + "... Stopped rowing");
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			System.err.println(rower.getLocalName() + ": Error managing message " + e.getMessage());
		}		
	}
	
	private void changeRowerWrapperKi(AID rowerAID, float ki) {
		for (RowerWrapper rowerWrapper : rower.getRowersWrapper()) {			
			if (rowerWrapper.getRowerAID().equals(rowerAID)) {
				rowerWrapper.setKi(ki);
				break;
			}
		}		
	}

	
	private MessageTemplate getTemplate() {
		MessageTemplate tRaceStarted = MessageTemplate.MatchProtocol(RaceStarted.class.getSimpleName());
		MessageTemplate tAssignBoat = MessageTemplate.MatchProtocol(AssignBoat.class.getSimpleName());
		MessageTemplate tRealRow = MessageTemplate.MatchProtocol(RealRow.class.getSimpleName());
		MessageTemplate tDenyRow = MessageTemplate.MatchProtocol(DenyRow.class.getSimpleName());
		MessageTemplate tPickSeat = MessageTemplate.MatchProtocol(PickSeat.class.getSimpleName());
		MessageTemplate tEnteringDock = MessageTemplate.MatchProtocol(EnteringDock.class.getSimpleName());
		MessageTemplate tRaceFinished = MessageTemplate.MatchProtocol(RaceFinished.class.getSimpleName());
		MessageTemplate tActivate = MessageTemplate.MatchProtocol(Rower.ACTIVATE_PROTOCOL);
		MessageTemplate tChangeSeat = MessageTemplate.MatchProtocol(Rower.CHANGE_SEAT_PROTOCOL);
		MessageTemplate tSendKi = MessageTemplate.MatchProtocol(Rower.SEND_KI_PROTOCOL);

		MessageTemplate template = MessageTemplate.or(tRaceStarted, 
			MessageTemplate.or(tAssignBoat, 
				MessageTemplate.or(tRealRow, 
					MessageTemplate.or(tDenyRow, 
						MessageTemplate.or(tPickSeat, 
							MessageTemplate.or(tEnteringDock, 
								MessageTemplate.or(tRaceFinished, 
									MessageTemplate.or(tActivate, 
										MessageTemplate.or(tChangeSeat, tSendKi)))))
						)
					)
				)
			);
		
		return template;
	}

}